{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Getting Started\n",
    "Before we begin, let us execute the below cell to display information about the NVIDIA® CUDA® driver and the GPUs running on the server by running the `nvidia-smi` command. To do this, execute the cell block below by clicking on it with your mouse, and pressing Ctrl+Enter, or pressing the play button in the toolbar above. You should see some output returned below the grey cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!nvidia-smi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since the code will be run on Multicore as well try running the cell below and get details of the nnumber of core and CPU architecure on the system"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "!cat /proc/cpuinfo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A MINI-CFD APPLICATION\n",
    "\n",
    "In this lab we will accelerate a Simple 2D regular-grid CFD simulation for teaching GPU programming using multiple approaches.\n",
    "This is a simple simulation of an incompressible fluid flowing in a cavity using the 2D Navier-Stokes equation. The fluid flow can either be viscous (finite Reynolds number and vortices in the flow) on non-viscous (no Reynolds\n",
    "number specified and no vortices in the flow).\n",
    "\n",
    "It is deliberately written to be very simple and easy to understand so it can be used as a teaching example.\n",
    "\n",
    "\n",
    "In this exercise the finite difference approach is used to determine the flow pattern of a fluid in a cavity. For simplicity, the liquid is assumed to have zero viscosity which implies that there can be no vortices (i.e. no whirlpools) in the flow. The cavity is a square box with an inlet on one side and an outlet on another as shown below:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"images/cfd_flow.png\" width=\"50%\" height=\"50%\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The objective of this exercise is not to dwell into the Maths part of it but to make use of different approaches to GPU programming to parallelize and improve the performance."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The general flow of the code is as shown in form of pseudo code"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```cpp\n",
    "set the boundary values for Ψ \n",
    "while (convergence == FALSE)  do \n",
    "    for each interior grid point do \n",
    "        update Ψ by averaging with its 4 nearest neighbours \n",
    "    end do \n",
    "    \n",
    "    check for convergence \n",
    "end do \n",
    "\n",
    "for each interior grid point do \n",
    "    calculate 𝑢𝑥 calculate 𝑢𝑦 \n",
    "end do\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Steps to follow\n",
    "We will follow the Optimization cycle for porting and improving the code performance.\n",
    "\n",
    "<img src=\"images/Optimization_Cycle.jpg\" width=\"80%\" height=\"80%\">\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Understand and Analyze the code\n",
    "Analyze the code and the Makefile for how to compile the code:\n",
    "\n",
    "[cfd code](../source_code/serial/cfd.cpp) \n",
    "\n",
    "[Makefile](../source_code/serial/Makefile)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Compile the code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "!cd ../source_code/serial && make clean && make"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run the CPU code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "jupyter": {
     "outputs_hidden": true
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "!cd ../source_code/serial && ./cfd 64 500"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Profiling\n",
    "\n",
    "For this section, we will be using Nsight systems profiler and as the code is a CPU code, we will be tracing NVTX APIs (already integrated to the application). NVTX is useful for tracing of CPU events and time ranges. For more info on Nsight profiler, please see the __[profiler documentation](https://docs.nvidia.com/nsight-systems/)__.\n",
    "\n",
    "### Viewing the profler output\n",
    "There are two ways to look at profiled code: \n",
    "\n",
    "1) Command line based: Use `nsys` to collect and view profiling data from the command-line. Profiling results are displayed in the console after the profiling data is collected.\n",
    "\n",
    "2) NVIDIA Nsight System: Open the Nsight System profiler and click on file > open, and choose the profiler output called `minicfd_profile.nsys-rep`. If you would like to view this on your local machine, this requires that the local system has CUDA toolkit installed of same version. More details on where to download CUDA toolit can be found in the links in resources section below."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Profile the CPU code to find hotspots"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!cd ../source_code/serial && nsys profile -t nvtx --stats=true --force-overwrite true -o minicfd_profile ./cfd 64 500\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Download and save the report file by holding down <mark>Shift</mark> and <mark>right-clicking</mark> [here](../source_code/serial/minicfd_profile.nsys-rep) then choosing <mark>save Link As</mark>. Once done, open it via the GUI."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "# Start Accelerating code\n",
    "\n",
    "[stdpar](minicfd_stdpar.ipynb)\n",
    "\n",
    "[OpenACC](minicfd_openacc.ipynb)\n",
    "\n",
    "[CUDA C](minicfd_cudac.ipynb)\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Final Results\n",
    "\n",
    "Modify and add timings for the accelerated code usinf different methods\n",
    "\n",
    "| | OpenACC |  stdpar | CUDA Languages ( C ) |\n",
    "| --- | --- |  --- | --- |\n",
    "| Multicore |   |  |  |\n",
    "| GPU  |  | |  |\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Licensing \n",
    "\n",
    "Copyright © 2022 OpenACC-Standard.org.  This material is released by OpenACC-Standard.org, in collaboration with NVIDIA Corporation, under the Creative Commons Attribution 4.0 International (CC BY 4.0). These materials may include references to hardware and software developed by other entities; all applicable licensing and copyrights apply."
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
